#include "GY_CalculationClass.h"
#include <QDebug>
#include <QVariant>
#include "../LuaUserData/GY_ColorUserData.h"
#include "../LuaUserData/GY_PointUserData.h"

static int ToFloat(lua_State* L) {
    QVariant value = lua_tonumber(L, 1);
    lua_pushnumber(L, value.toFloat());
    return 1;
}

static int NOT(lua_State* L) {
    bool value = !lua_tonumber(L, 1);
    lua_pushnumber(L, value);
    return 1;
}

static int IfElse(lua_State* L) {
    bool value = lua_toboolean(L, 1);
    if(value) {
        lua_pushnumber(L, lua_tonumber(L, 2));
    }else {
        lua_pushnumber(L, lua_tonumber(L, 3));
    }
    return 1;
}

GY_CalculationClass::GY_CalculationClass(QObject *parent) : QObject(parent)
{
    m_pLua = luaL_newstate();
    luaL_openlibs(m_pLua);

    lua_register(m_pLua, "ToFloat", ToFloat);
    lua_register(m_pLua, "IfElse", IfElse);
    lua_register(m_pLua, "NOT", NOT);
    setUserData();
}

//void* luaL_testudata(lua_State* L, int idx, const char* tname) {
//    void* p = lua_touserdata(L, idx);
//    if (p != NULL) {  // userdata 是否为 NULL
//        if (lua_getmetatable(L, idx)) {  // 是否有元表
//            lua_getfield(L, LUA_REGISTRYINDEX, tname);  // 获取期望的元表
//            if (lua_rawequal(L, -1, -2)) {  // 比较元表是否一致
//                lua_pop(L, 2);  // 弹出元表
//                return p;  // 类型匹配，返回指针
//            }
//            lua_pop(L, 2);  // 弹出元表
//        }
//    }
//    return nullptr;  // 类型不匹配，返回 null 指针
//}

bool GY_CalculationClass::formulaCalculation(const QString &name, const PropertyType& type)
{
    //注册全局变量
    if(type == PointPropertyType) {
        //point结构体
        Point point = {0, 0};
        Point* p1 = static_cast<Point*>(lua_newuserdata(m_pLua, sizeof(Point)));
        *p1 = point;
        luaL_getmetatable(m_pLua, "Point");
        lua_setmetatable(m_pLua, -2);
        lua_setglobal(m_pLua, name.toLatin1().data());
        m_pointVarMap.insert(name,p1);
    }else if(type == ColorPropertyType) {
        //color结构体
        Color color = {0, 0, 0, 0};
        Color* c1 = static_cast<Color*>(lua_newuserdata(m_pLua, sizeof(Color)));
        *c1 = color;
        luaL_getmetatable(m_pLua, "Color");
        lua_setmetatable(m_pLua, -2);
        lua_setglobal(m_pLua, name.toLatin1().data());
    }else if(type == QStringPropertyType) {
        //string
        lua_pushstring(m_pLua, "");
        lua_setglobal(m_pLua, name.toLatin1().data());
    }else if(type == IntPropertyType) {
        //int
        lua_pushinteger(m_pLua, 0);
        lua_setglobal(m_pLua, name.toLatin1().data());
    }else {
        //double
        lua_pushnumber(m_pLua, 0);
        lua_setglobal(m_pLua, name.toLatin1().data());
    }
    return true;
}

void GY_CalculationClass::propertyChange(const QString &name, const QVariant &value, const PropertyType &type)
{
    //修改全局变量值
    if(type == PointPropertyType) {
        //用指针直接修改点的数据
        Point point = {value.toPointF().x(), value.toPointF().y()};
        *m_pointVarMap[name] = point;

    }else if(type == ColorPropertyType) {
        QString valName = name + ".r" + "=" + QString::number(value.value<QColor>().red());
        luaL_loadstring(m_pLua, valName.toLatin1().data());
        lua_pcall(m_pLua, 0, 1, 0);

        valName = name + ".g" + "=" + QString::number(value.value<QColor>().green());
        luaL_loadstring(m_pLua, valName.toLatin1().data());
        lua_pcall(m_pLua, 0, 1, 0);

        valName = name + ".b" + "=" + QString::number(value.value<QColor>().blue());
        luaL_loadstring(m_pLua, valName.toLatin1().data());
        lua_pcall(m_pLua, 0, 1, 0);

        valName = name + ".a" + "=" + QString::number(value.value<QColor>().alpha());
        luaL_loadstring(m_pLua, valName.toLatin1().data());
        lua_pcall(m_pLua, 0, 1, 0);

    }else if(type == QStringPropertyType) {
        QString valName = name + "=" + "'" + value.toString() + "'";
        //中文字符串需要转为UTF-8编码格式
        luaL_loadstring(m_pLua, valName.toUtf8().data());
        lua_pcall(m_pLua, 0, 1, 0);

    }else if(type == IntPropertyType) {
        QString valName = name + "=" + QString::number(value.toInt());
        luaL_loadstring(m_pLua, valName.toLatin1().data());
        lua_pcall(m_pLua, 0, 1, 0);

    }else if(type == FloatPropertyType) {
        QString valName = name + "=" + QString::number(value.toFloat());
        luaL_loadstring(m_pLua, valName.toLatin1().data());
        lua_pcall(m_pLua, 0, 1, 0);

    }else if(type == DoublePropertyType) {
        QString valName = name + "=" + QString::number(value.toDouble());
        luaL_loadstring(m_pLua, valName.toLatin1().data());
        lua_pcall(m_pLua, 0, 1, 0);

    }else {
        QString valName = name + "=" + QString::number(value.toReal());
        luaL_loadstring(m_pLua, valName.toLatin1().data());
        lua_pcall(m_pLua, 0, 1, 0);
    }
}

QString GY_CalculationClass::getSourceValue(QMap<QString, BindingInformation> &map, const QString &name)
{
    //一个变量下多个绑定信息
    int mapNamePurposeSize = map[name].purpose.size();
    for (int i=0;i<mapNamePurposeSize;i++) {
        if (luaL_loadstring(m_pLua, map[name].source.at(i).toUtf8().data()) || lua_pcall(m_pLua, 0, 1, 0)) {
//            qDebug() << lua_tostring(m_pLua, -1);
            return "Failed to parse expression: " + QString(lua_tostring(m_pLua, -1));
        }
        if(!lua_isuserdata(m_pLua ,-1))
        {
            if(map[name].varType == QStringPropertyType) {
                QString result(lua_tostring(m_pLua, -1));
                map[name].value[i] = result;
            }else if(map[name].varType == IntPropertyType) {
                int result = lua_tonumber(m_pLua, -1);//lua整除号'//'
                map[name].value[i] = result;
            }else {
                double result = lua_tonumber(m_pLua, -1);
                map[name].value[i] = result;
            }
//            qDebug() << "计算结果Value = (" <<result << ")" ;
        }
        else
        {
            void* pData=nullptr;
            const char* typeName=luaL_getUdataName(m_pLua,-1,pData);
//            qDebug() <<"TypeName:"<<typeName;
            if(!strcmp(typeName,"point"))
            {
                //point
                Point* p = static_cast<Point*>(pData);
//                qDebug() << "计算点point(" << p->x << ", " << p->y << ")" ;
                QPointF value(p->X,p->Y);
                map[name].value[i] = value;
            }
            if(!strcmp(typeName,"color")) {
                //color
                Color* p = static_cast<Color*>(pData);
//                qDebug() << "计算点color(" << p->r << ", " << p->g << ", " << p->b << ", " << p->a << ")" ;
                QColor value(p->r,p->g,p->b,p->a);
                map[name].value[i] = value;
            }
        }
    }
    return "OK";
}

void GY_CalculationClass::deleteVar(const QString& name)
{
    QString valName = name + "=" + "nil";
    luaL_loadstring(m_pLua, valName.toLatin1().data());
    lua_pcall(m_pLua, 0, 1, 0);
//    lua_State::free  释放指针
//    m_pointVarMap[name] = nullptr;
    m_pointVarMap.remove(name);
}

GY_CalculationClass::~GY_CalculationClass()
{
    lua_close(m_pLua);
}

void GY_CalculationClass::setUserData()
{
    //point注册元表
    luaL_newmetatable(m_pLua, "Point");
    lua_pushstring(m_pLua, "point");
    lua_setfield(m_pLua, -2, "__name");

    lua_pushstring(m_pLua, "__add");
    lua_pushcfunction(m_pLua, add_point);
    lua_settable(m_pLua, -3);

    lua_pushstring(m_pLua, "__sub");
    lua_pushcfunction(m_pLua, sub_point);
    lua_settable(m_pLua, -3);

    lua_pushstring(m_pLua, "__mul");
    lua_pushcfunction(m_pLua, mul_point);
    lua_settable(m_pLua, -3);

    lua_pushstring(m_pLua, "__div");
    lua_pushcfunction(m_pLua, div_point);
    lua_settable(m_pLua, -3);

    lua_pushstring(m_pLua, "__index");
    lua_pushcfunction(m_pLua, point_index);
    lua_settable(m_pLua, -3);

    lua_pushstring(m_pLua, "__newindex");
    lua_pushcfunction(m_pLua, point_newindex);
    lua_settable(m_pLua, -3);


    //color注册元表
    luaL_newmetatable(m_pLua, "Color");
    lua_pushstring(m_pLua, "color");
    lua_setfield(m_pLua, -2, "__name");

    lua_pushstring(m_pLua, "__index");
    lua_pushcfunction(m_pLua, color_index);
    lua_settable(m_pLua, -3);

    lua_pushstring(m_pLua, "__newindex");
    lua_pushcfunction(m_pLua, color_newindex);
    lua_settable(m_pLua, -3);
}








